<?php
namespace App\Services;

use App\Exceptions\AlipayException;
use App\Exceptions\QqpayException;
use App\Exceptions\WechatException;
use App\Jobs\OrdersNotify;
use App\Models\Channel;
use App\Models\Merchant;
use App\Models\Order;
use App\Pay\Config\Config;
use App\Pay\Pay;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class PayNotifyService
{
    public function notify($gateway, Channel $channel)
    {
        Log::debug(print_r(request()->getContent(), true));
        return method_exists($this, $gateway) ? $this->{$gateway}($channel) : '';
    }



    public function wxpay(Channel $channel)
    {
        DB::beginTransaction();
        try {
            $wechat = Pay::wechat(new Config([
                'mch_id' => $channel->mch_id,
                'mch_key' => $channel->mch_key,
                'mp_appid' => $channel->mp_appid,
                'notify_url' => route('pay.notify', ['gateway' => Order::GATEWAY_WECHAT, 'channel' => $channel->id]),
            ]));
            $result = $wechat->verify();
            // 验证支付状态
            if ($result['result_code'] != 'SUCCESS' && $result['return_code'] != 'SUCCESS') {
                throw new WechatException('支付未完成');
            }
            // 修改订单状态
            $order = Order::getOrderByTradeNo($result['out_trade_no'], Order::STATUS_UNPAID);
            $order->status = Order::STATUS_PAID;
            $order->pay_amount = $result['total_fee'] / 100;
            $order->pay_user = $result['openid'];
            $order->payment_no = $result['transaction_id'];
            $order->paid_at = date('Y-m-d H:i:s');
            $order->save();

            // 异步提醒
            $this->notifyMerchant($order);
            // 增加余额
            $merchantService = new MerchantService();
            $merchantService->incrementBalance($order->merchant, calculate_amount($order->pay_amount, $channel->rate), 'system', '订单：' . $order->trade_no);

            DB::commit();
            return $wechat->success();
        } catch (\Exception $e) {
            DB::rollBack();
            report($e);
        }
    }

    public function alipay(Channel $channel)
    {
        DB::beginTransaction();
        try {
            $alipay = Pay::alipay(new Config([
                'mch_id' => $channel->mch_id,
                'public_key' => $channel->public_key,
                'private_key' => $channel->private_key,
                'notify_url' => route('pay.notify', ['gateway' => Order::GATEWAY_ALI, 'channel' => $channel->id]),
            ]));
            $result = $alipay->verify();

            // 验证支付状态
            if ($result['trade_status'] != 'TRADE_SUCCESS' && $result['trade_status'] != 'TRADE_FINISHED') {
                throw new AlipayException('支付未完成');
            }

            Log::debug(print_r($result, true));
            // 修改订单状态
            $order = Order::getOrderByTradeNo($result['out_trade_no'], Order::STATUS_UNPAID);
            $order->status = Order::STATUS_PAID;
            $order->pay_amount = $result['buyer_pay_amount'];
            $order->pay_user = $result['buyer_id'];
            $order->payment_no = $result['trade_no'];
            $order->paid_at = date('Y-m-d H:i:s');
            $order->save();

            // 异步提醒
            $this->notifyMerchant($order);
            // 增加余额
            $merchantService = new MerchantService();
            $merchantService->incrementBalance($order->merchant, calculate_amount($order->pay_amount, $channel->rate), 'system', '订单：' . $order->trade_no);

            DB::commit();
            return $alipay->success();
        } catch (\Exception $e) {
            DB::rollBack();
            report($e);
        }
    }

    public function qqpay(Channel $channel)
    {
        DB::beginTransaction();
        try {
            $qqpay = Pay::qqpay(new Config([
                'mch_id' => $channel->mch_id,
                'mch_key' => $channel->mch_key,
                'notify_url' => route('pay.notify', ['gateway' => Order::GATEWAY_QQ, 'channel' => $channel->id]),
            ]));
            $result = $qqpay->verify();

            // 验证支付状态
            if ($result['trade_state'] != 'SUCCESS') {
                throw new QqpayException('支付未完成');
            }

            // 修改订单状态
            $order = Order::getOrderByTradeNo($result['out_trade_no'], Order::STATUS_UNPAID);
            $order->status = Order::STATUS_PAID;
            $order->pay_amount = $result['total_fee'] /  100;
            $order->pay_user = $result['openid'] ?? 'qquser';
            $order->payment_no = $result['transaction_id'];
            $order->paid_at = date('Y-m-d H:i:s');
            $order->save();
            Log::debug(print_r($order->toArray(), true));

            // 异步提醒
            $this->notifyMerchant($order);
            // 增加商户余额
            $merchantService = new MerchantService();
            $merchantService->incrementBalance($order->merchant, calculate_amount($order->pay_amount, $channel->rate), 'system', '订单：' . $order->trade_no);

            DB::commit();
            return $qqpay->success();
        } catch (\Exception $e) {
            DB::rollBack();
            report($e);
        }
    }

    // 易支付模式提醒
    public function notifyMerchant(Order $order)
    {
        $merchant = $order->merchant;
        switch ($merchant->notify_type) {
            case Merchant::NOTIFY_TYPE_NORMAL:

                break;
            case Merchant::NOTIFY_TYPE_EPAY:
                $params = $this->getNotifyParams($order);
                if (Str::contains(rtrim($order->notify_url, '?'), '?')) {
                    $notifyUrl = rtrim($order->notify_url, '?') . '&' . urldecode(http_build_query($params));
                } else {
                    $notifyUrl = rtrim($order->notify_url, '?') . '?' . urldecode(http_build_query($params));
                }
                $client = (new Client())->get($notifyUrl);
                $result = $client->getBody()->getContents();
                Log::debug($result);
                if ('success' !== strtolower($result)) {
                    $this->asyncNotify($order);
                }
                break;
        }
    }

    public function getNotifyParams(Order $order)
    {
        $merchant = $order->merchant;
        switch ($merchant->notify_type) {
            case Merchant::NOTIFY_TYPE_NORMAL:

                return [];
            case Merchant::NOTIFY_TYPE_EPAY:
                $params = [
                    'pid' => $merchant->client_id,
                    'trade_no' => $order->trade_no,
                    'out_trade_no' => $order->out_trade_no,
                    'type' => $order->gateway,
                    'name' => $order->title,
                    'money' => $order->pay_amount,
                    'trade_status' => 'TRADE_SUCCESS',
                    'sign_type' => 'MD5',
                ];
                $params['sign'] = epay_sign($params, $merchant->client_secret);
                return $params;
        }
    }

    /**
     * @param Order $order
     */
    public function asyncNotify(Order $order)
    {
        return OrdersNotify::dispatch($order)->delay(0);
    }
}
